﻿#include <stdio.h>
#include <string.h>
#include <iostream>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "libutils.h"
#include "protocol.h"
#include "concentrator.h"

using namespace std;

void show_menu(void);

concentrator c;

/* MAC */
void concentrator::set_mac(char *buf)
{
	strcpy(MAC, buf);
}

char *concentrator::get_mac(void)
{
	char *p = MAC;
	return p;
}

/* time */
void concentrator::set_time(time_t t)
{
	ltime = t;
}

time_t concentrator::get_time(void)
{
	return ltime;
}

/* init: set MAC and time... */
void concentrator::init(void)
{
	char macstr[13];
	strcpy(macstr, "0000A3438966");

	set_mac(macstr);
	set_time(time(NULL));
}

void concentrator::run(void)
{
	readmeter();
}

//设置为非阻塞
void set_nonblock(int fd)
{
	int flag;
	flag = fcntl(fd, F_GETFL, 0);
	flag |= O_NONBLOCK;
	fcntl(fd, F_SETFL, flag);
	//printf("set nonblock\n");
}

void concentrator::readmeter(void)
{
	char choice;
	
	/* set socket */
	int sockid;
	struct sockaddr_in servaddr;
	socklen_t addrlen;

	sockid = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockid < 0) {
		perror("Open socke fails.");
		exit(1);
	}

	bzero(&servaddr, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	servaddr.sin_port = htons(2345);
	/* set socket end */

	/* set sockid as non-block */
	set_nonblock(sockid);

	while(1) {
		Datagram *pd;
		show_menu();
		cout<<"请选择功能：";
		cin>>choice;

		switch(choice) {
		case '1':
			cout<<"控制电表（376）"<<endl;
			cin>>tx_buf;

			{
				__u8 *p, *q;
				__u8 len;
				int i = 0;

				p = (__u8*)malloc(strlen((char*)tx_buf)/2);
				q = (__u8*)malloc(strlen((char*)tx_buf)/2);
			
				str2hex((__u8*)tx_buf, p, strlen((char*)tx_buf));

				printf("报文内容：");
				mem_dump(p, strlen((char*)tx_buf)/2);
				pd = ParseDatagram((__u8*)p, strlen((char*)tx_buf)/2);
				show_Datagram(pd);

				//从376.2报文中解析出645报文，放到q中
				do_Datagram(pd, &q, &len);
				//mem_dump(q, len);

				//发送645报文
				sendto(sockid, q, len, 0,
					(struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));

				//非阻塞方式，许多多读一些时间
				//可以用select判断超时来优化
				while(i++<10000)
				recvfrom(sockid, rx_buf,sizeof(rx_buf), 0,
					(struct sockaddr *)&servaddr, &addrlen);
				printf("%s\n", rx_buf);

				memset(rx_buf, 0, BUFSIZ);
				memset(tx_buf, 0, BUFSIZ);
				//释放内存
				free(p);
			}
			break;
		case '5':
			cout<<"控制命令（645）"<<endl;
			cin>>tx_buf;
			{
				__u8 *p;
				p = (__u8*)malloc(strlen((char*)tx_buf)/2);
			
				str2hex((__u8*)tx_buf, p, strlen((char*)tx_buf));

				mem_dump(p, strlen((char*)tx_buf)/2);
				//发送
				sendto(sockid, p, strlen((char*)tx_buf)/2, 0,
					(struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));

				recvfrom(sockid, rx_buf,sizeof(rx_buf), 0,
					(struct sockaddr *)&servaddr, &addrlen);
				printf("%s\n", rx_buf);
				memset(rx_buf, 0, BUFSIZ);
				memset(tx_buf, 0, BUFSIZ);
				//释放内存
				free(p);
			}

			break;
		case 'E':
		case 'e':
			cout<<"读表数据"<<endl;
			cin>>tx_buf;
			{
				int i = 0;
				__u8 *p;
				p = (__u8*)malloc(strlen((char*)tx_buf)/2);
			
				str2hex((__u8*)tx_buf, p, strlen((char*)tx_buf));

				//发送
				sendto(sockid, p, strlen((char*)tx_buf)/2, 0,
					(struct sockaddr *)&servaddr, sizeof(struct sockaddr_in));

				//非阻塞方式，许多多读一些时间
				//可以用select判断超时来优化
				while(i++<10000)
				recvfrom(sockid, rx_buf,sizeof(rx_buf), 0,
					(struct sockaddr *)&servaddr, &addrlen);
				printf("%s\n", rx_buf);
				memset(rx_buf, 0, BUFSIZ);
				memset(tx_buf, 0, BUFSIZ);
				//释放内存
				free(p);
			}

			break;

		case 'P':
		case 'p':
			cin>>tx_buf;

			{
				//int i = 0;
				__u8 *p;
				p = (__u8*)malloc(strlen((char*)tx_buf)/2);
			
				str2hex((__u8*)tx_buf, p, strlen((char*)tx_buf));

				printf("报文内容：");
				mem_dump(p, strlen((char*)tx_buf)/2);
				pd = ParseDatagram((__u8*)p, strlen((char*)tx_buf)/2);
				show_Datagram(pd);

				memset(rx_buf, 0, BUFSIZ);
				memset(tx_buf, 0, BUFSIZ);
				//释放内存
				free(p);
			}

			break;
		case 'Q':
		case 'q':
			cout<<"正在退出..."<<endl;
			exit(0);
		}

		sleep(1);
	}
}

void show_menu(void)
{
	printf("\n-----COMMAND-----\n"
		//"1. AFN=01H Init\n"
		//"3. AFN=03H Query\n"
		"1. 控制电表（376.2）\n"
		//"5. 控制电表（645）\n"
		//"E. 读取电表（645）\n"
		"P. 解析376.2报文\n"
		//"M. 封装376.2报文\n"
		"Q. 退出\n");
}

int main(int argc, char **argv)
{
	c.init();
	c.run();

	return 0;
}
